package cn.lx.elasticsearch.autocomplete.service.impl;

import cn.lx.elasticsearch.autocomplete.dto.SuggestRequest;
import cn.lx.elasticsearch.autocomplete.dto.SuggestResponse;
import cn.lx.elasticsearch.autocomplete.entity.City;
import cn.lx.elasticsearch.autocomplete.entity.Product;
import cn.lx.elasticsearch.autocomplete.entity.User;
import cn.lx.elasticsearch.autocomplete.repository.CityRepository;
import cn.lx.elasticsearch.autocomplete.repository.ProductRepository;
import cn.lx.elasticsearch.autocomplete.repository.UserRepository;
import cn.lx.elasticsearch.autocomplete.service.AutocompleteService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
import static org.elasticsearch.index.query.QueryBuilders.wildcardQuery;
import static org.elasticsearch.search.suggest.SuggestBuilders.completionSuggestion;

/**
 * 自动补全服务实现类
 *
 * @author lx
 * @since 2024-01-01
 */
@Slf4j
@Service
public class AutocompleteServiceImpl implements AutocompleteService {

    @Autowired
    private ElasticsearchOperations elasticsearchOperations;

    @Autowired
    private ProductRepository productRepository;

    @Autowired
    private CityRepository cityRepository;

    @Autowired
    private UserRepository userRepository;

    @Value("${autocomplete.index.product-index:products}")
    private String productIndex;

    @Value("${autocomplete.index.city-index:cities}")
    private String cityIndex;

    @Value("${autocomplete.index.user-index:users}")
    private String userIndex;

    @Override
    public SuggestResponse<Product> suggestProducts(SuggestRequest request) {
        return suggest(request, Product.class);
    }

    @Override
    public SuggestResponse<City> suggestCities(SuggestRequest request) {
        return suggest(request, City.class);
    }

    @Override
    public SuggestResponse<User> suggestUsers(SuggestRequest request) {
        return suggest(request, User.class);
    }

    @Override
    public <T> SuggestResponse<T> suggest(SuggestRequest request, Class<T> clazz) {
        long startTime = System.currentTimeMillis();

        try {
            String indexName = getIndexName(request.getIndexType());
            String fieldName = getFieldName(request.getIndexType());

            log.info("执行自动补全查询 - 索引: {}, 字段: {}, 关键词: {}", indexName, fieldName, request.getKeyword());

            // 构建匹配查询 - 使用 match 查询支持中文分词
            NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(matchQuery(fieldName, request.getKeyword()))
                .withPageable(org.springframework.data.domain.PageRequest.of(0, request.getSize()))
                .build();

            // 执行搜索
            SearchHits<T> searchHits = elasticsearchOperations.search(searchQuery, clazz);

            log.info("搜索结果数量: {}", searchHits.getTotalHits());

            // 处理结果
            List<SuggestResponse.SuggestionItem<T>> suggestions = new ArrayList<>();
            for (SearchHit<T> hit : searchHits) {
                SuggestResponse.SuggestionItem<T> item = new SuggestResponse.SuggestionItem<>();
                item.setText(getTextFromHit(hit, fieldName));
                item.setScore(hit.getScore());
                item.setSource(hit.getContent());
                item.setType(request.getIndexType());

                // 高亮处理
                if (request.getHighlight()) {
                    item.setHighlightedText(highlightText(item.getText(), request.getKeyword()));
                }

                suggestions.add(item);
            }

            long took = System.currentTimeMillis() - startTime;
            
            return new SuggestResponse<>(
                suggestions,
                (long) suggestions.size(),
                took,
                true,
                null
            );

        } catch (Exception e) {
            log.error("自动补全查询失败", e);
            long took = System.currentTimeMillis() - startTime;
            return new SuggestResponse<>(
                new ArrayList<>(),
                0L,
                took,
                false,
                e.getMessage()
            );
        }
    }

    @Override
    public void batchSaveProducts(List<Product> products) {
        try {
            productRepository.saveAll(products);
            log.info("批量保存商品数据成功，数量：{}", products.size());
        } catch (Exception e) {
            log.error("批量保存商品数据失败", e);
            throw new RuntimeException("批量保存商品数据失败", e);
        }
    }

    @Override
    public void batchSaveCities(List<City> cities) {
        try {
            cityRepository.saveAll(cities);
            log.info("批量保存城市数据成功，数量：{}", cities.size());
        } catch (Exception e) {
            log.error("批量保存城市数据失败", e);
            throw new RuntimeException("批量保存城市数据失败", e);
        }
    }

    @Override
    public void batchSaveUsers(List<User> users) {
        try {
            userRepository.saveAll(users);
            log.info("批量保存用户数据成功，数量：{}", users.size());
        } catch (Exception e) {
            log.error("批量保存用户数据失败", e);
            throw new RuntimeException("批量保存用户数据失败", e);
        }
    }

    @Override
    public void initTestData() {
        log.info("开始初始化测试数据...");
        
        // 初始化商品数据
        initProductData();
        
        // 初始化城市数据
        initCityData();
        
        // 初始化用户数据
        initUserData();
        
        log.info("测试数据初始化完成");
    }

    /**
     * 获取索引名称
     */
    private String getIndexName(String indexType) {
        switch (indexType.toLowerCase()) {
            case "product":
                return productIndex;
            case "city":
                return cityIndex;
            case "user":
                return userIndex;
            default:
                throw new IllegalArgumentException("不支持的索引类型：" + indexType);
        }
    }

    /**
     * 获取字段名称
     */
    private String getFieldName(String indexType) {
        switch (indexType.toLowerCase()) {
            case "product":
                return "name";
            case "city":
                return "name";
            case "user":
                return "username";
            default:
                throw new IllegalArgumentException("不支持的索引类型：" + indexType);
        }
    }

    /**
     * 从搜索结果中获取文本
     */
    private String getTextFromHit(SearchHit<?> hit, String fieldName) {
        Object content = hit.getContent();
        if (content instanceof Product) {
            return ((Product) content).getName();
        } else if (content instanceof City) {
            return ((City) content).getName();
        } else if (content instanceof User) {
            return ((User) content).getUsername();
        }
        return "";
    }

    /**
     * 高亮文本
     */
    private String highlightText(String text, String keyword) {
        if (!StringUtils.hasText(keyword)) {
            return text;
        }
        return text.replaceAll("(?i)" + keyword, "<em>" + keyword + "</em>");
    }

    /**
     * 初始化商品数据
     */
    private void initProductData() {
        List<Product> products = new ArrayList<>();

        // 电子产品
        products.add(createProduct("iPhone 15 Pro", "苹果最新旗舰手机", "电子产品", "苹果", 9999.00, 100));
        products.add(createProduct("iPhone 15", "苹果新款手机", "电子产品", "苹果", 7999.00, 150));
        products.add(createProduct("MacBook Pro", "苹果笔记本电脑", "电子产品", "苹果", 15999.00, 50));
        products.add(createProduct("iPad Air", "苹果平板电脑", "电子产品", "苹果", 4999.00, 80));

        // 华为产品
        products.add(createProduct("华为Mate 60 Pro", "华为旗舰手机", "电子产品", "华为", 6999.00, 120));
        products.add(createProduct("华为P60", "华为拍照手机", "电子产品", "华为", 4999.00, 100));
        products.add(createProduct("华为MateBook", "华为笔记本电脑", "电子产品", "华为", 5999.00, 60));

        // 小米产品
        products.add(createProduct("小米14 Pro", "小米旗舰手机", "电子产品", "小米", 3999.00, 200));
        products.add(createProduct("小米13", "小米手机", "电子产品", "小米", 2999.00, 180));
        products.add(createProduct("小米笔记本", "小米笔记本电脑", "电子产品", "小米", 3999.00, 90));

        // 服装
        products.add(createProduct("Nike运动鞋", "耐克运动鞋", "服装", "Nike", 899.00, 300));
        products.add(createProduct("Adidas运动服", "阿迪达斯运动服", "服装", "Adidas", 599.00, 250));
        products.add(createProduct("优衣库T恤", "优衣库基础T恤", "服装", "优衣库", 99.00, 500));

        batchSaveProducts(products);
    }

    /**
     * 初始化城市数据
     */
    private void initCityData() {
        List<City> cities = new ArrayList<>();

        // 一线城市
        cities.add(createCity("北京", "北京市", "中国", "BJ", 21540000L, 1, 116.4074, 39.9042));
        cities.add(createCity("上海", "上海市", "中国", "SH", 24870000L, 1, 121.4737, 31.2304));
        cities.add(createCity("广州", "广东省", "中国", "GZ", 15300000L, 1, 113.2644, 23.1291));
        cities.add(createCity("深圳", "广东省", "中国", "SZ", 17560000L, 1, 114.0579, 22.5431));

        // 二线城市
        cities.add(createCity("杭州", "浙江省", "中国", "HZ", 11940000L, 2, 120.1551, 30.2741));
        cities.add(createCity("南京", "江苏省", "中国", "NJ", 9310000L, 2, 118.7674, 32.0415));
        cities.add(createCity("武汉", "湖北省", "中国", "WH", 12327000L, 2, 114.2986, 30.5844));
        cities.add(createCity("成都", "四川省", "中国", "CD", 20940000L, 2, 104.0668, 30.5728));

        // 三线城市
        cities.add(createCity("西安", "陕西省", "中国", "XA", 12950000L, 3, 108.9402, 34.3416));
        cities.add(createCity("青岛", "山东省", "中国", "QD", 10070000L, 3, 120.3826, 36.0671));
        cities.add(createCity("大连", "辽宁省", "中国", "DL", 7450000L, 3, 121.6147, 38.9140));
        cities.add(createCity("厦门", "福建省", "中国", "XM", 5280000L, 3, 118.1100, 24.4900));

        batchSaveCities(cities);
    }

    /**
     * 初始化用户数据
     */
    private void initUserData() {
        List<User> users = new ArrayList<>();

        users.add(createUser("张三", "张三", "zhangsan@example.com", "13800138001", 25, 1, "北京", "程序员"));
        users.add(createUser("李四", "李四", "lisi@example.com", "13800138002", 30, 1, "上海", "设计师"));
        users.add(createUser("王五", "王五", "wangwu@example.com", "13800138003", 28, 2, "广州", "产品经理"));
        users.add(createUser("赵六", "赵六", "zhaoliu@example.com", "13800138004", 35, 1, "深圳", "架构师"));
        users.add(createUser("钱七", "钱七", "qianqi@example.com", "13800138005", 26, 2, "杭州", "UI设计师"));
        users.add(createUser("孙八", "孙八", "sunba@example.com", "13800138006", 32, 1, "南京", "测试工程师"));
        users.add(createUser("周九", "周九", "zhoujiu@example.com", "13800138007", 29, 1, "武汉", "运维工程师"));
        users.add(createUser("吴十", "吴十", "wushi@example.com", "13800138008", 27, 2, "成都", "数据分析师"));

        batchSaveUsers(users);
    }

    /**
     * 创建商品对象
     */
    private Product createProduct(String name, String description, String category, String brand,
                                Double price, Integer stock) {
        Product product = new Product();
        product.setId(UUID.randomUUID().toString());
        product.setName(name);
        product.setDescription(description);
        product.setCategory(category);
        product.setBrand(brand);
        product.setPrice(new java.math.BigDecimal(price));
        product.setStock(stock);
        product.setStatus(1);
        product.setRating(4.5);
        product.setSales(1000L);
        product.setCreateTime(LocalDateTime.now().toLocalDate().atStartOfDay());
        product.setUpdateTime(LocalDateTime.now().toLocalDate().atStartOfDay());
        return product;
    }

    /**
     * 创建城市对象
     */
    private City createCity(String name, String province, String country, String code,
                          Long population, Integer level, Double longitude, Double latitude) {
        City city = new City();
        city.setId(UUID.randomUUID().toString());
        city.setName(name);
        city.setProvince(province);
        city.setCountry(country);
        city.setCode(code);
        city.setPopulation(population);
        city.setLevel(level);
        city.setLongitude(longitude);
        city.setLatitude(latitude);
        city.setDescription(name + "是" + province + "的省会城市");
        return city;
    }

    /**
     * 创建用户对象
     */
    private User createUser(String username, String realName, String email, String phone,
                          Integer age, Integer gender, String city, String profession) {
        User user = new User();
        user.setId(UUID.randomUUID().toString());
        user.setUsername(username);
        user.setRealName(realName);
        user.setEmail(email);
        user.setPhone(phone);
        user.setAge(age);
        user.setGender(gender);
        user.setCity(city);
        user.setProfession(profession);
        user.setStatus(1);
        user.setLevel(1);
        user.setPoints(1000L);
        user.setRegisterTime(LocalDateTime.now().toLocalDate().atStartOfDay());
        user.setLastLoginTime(LocalDateTime.now().toLocalDate().atStartOfDay());
        return user;
    }
}
